{
  "cells": [
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "4EFY9e5wRn7v"
      },
      "source": [
        "##### Copyright 2020 The TensorFlow Authors."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "cellView": "form",
        "id": "pkTRazeVRwDe"
      },
      "outputs": [],
      "source": [
        "#@title Licensed under the Apache License, Version 2.0 (the \"License\");\n",
        "# you may not use this file except in compliance with the License.\n",
        "# You may obtain a copy of the License at\n",
        "#\n",
        "# https://www.apache.org/licenses/LICENSE-2.0\n",
        "#\n",
        "# Unless required by applicable law or agreed to in writing, software\n",
        "# distributed under the License is distributed on an \"AS IS\" BASIS,\n",
        "# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n",
        "# See the License for the specific language governing permissions and\n",
        "# limitations under the License."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "VyOckJu6Rs-i"
      },
      "source": [
        "# 데이터 증강"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "0HEsULqDR7AH"
      },
      "source": [
        "<table class=\"tfo-notebook-buttons\" align=\"left\">\n",
        "  <td><a target=\"_blank\" href=\"https://www.tensorflow.org/tutorials/images/data_augmentation\"><img src=\"https://www.tensorflow.org/images/tf_logo_32px.png\">TensorFlow.org에서 보기</a></td>\n",
        "  <td><a target=\"_blank\" href=\"https://colab.research.google.com/github/tensorflow/docs-l10n/blob/master/site/ko/tutorials/images/data_augmentation.ipynb\"><img src=\"https://www.tensorflow.org/images/colab_logo_32px.png\">Google Colab에서 실행</a></td>\n",
        "  <td><a target=\"_blank\" href=\"https://github.com/tensorflow/docs-l10n/blob/master/site/ko/tutorials/images/data_augmentation.ipynb\"><img src=\"https://www.tensorflow.org/images/GitHub-Mark-32px.png\">GitHub에서 소스 보기</a></td>\n",
        "  <td><a href=\"https://storage.googleapis.com/tensorflow_docs/docs-l10n/site/ko/tutorials/images/data_augmentation.ipynb\"><img src=\"https://www.tensorflow.org/images/download_logo_32px.png\">노트북 다운로드</a></td>\n",
        "</table>"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "PxIOE5RnSQtj"
      },
      "source": [
        "## 개요\n",
        "\n",
        "이 튜토리얼에서는 이미지 회전과 같은 무작위(그러나 사실적인) 변환을 적용하여 훈련 세트의 다양성을 증가시키는 기술인 데이터 증강의 예를 보여줍니다. 두 가지 방법으로 데이터 증강을 적용하는 방법을 배웁니다. 먼저, [Keras 전처리 레이어](https://www.tensorflow.org/api_docs/python/tf/keras/layers/experimental/preprocessing/)를 사용하고, 그 다음으로 `tf.image`를 사용합니다."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "-UxHAqXmSXN5"
      },
      "source": [
        "## 설정"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "jGIrHH4P013K"
      },
      "outputs": [],
      "source": [
        "!pip install tf-nightly"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "C2Q5rPenTAJP"
      },
      "outputs": [],
      "source": [
        "import matplotlib.pyplot as plt\n",
        "import numpy as np\n",
        "import tensorflow as tf\n",
        "import tensorflow_datasets as tfds\n",
        "\n",
        "from tensorflow.keras import layers\n",
        "from tensorflow.keras.datasets import mnist"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "Ydx3SSoF4wpG"
      },
      "source": [
        "## 데이터세트 다운로드\n",
        "\n",
        "이 튜토리얼에서는 [tf_flowers](https://www.tensorflow.org/datasets/catalog/tf_flowers) 데이터세트를 사용합니다. 편의를 위해 [TensorFlow Datasets](https://www.tensorflow.org/datasets)를 사용하여 데이터세트를 다운로드합니다. 데이터를 가져오는 다른 방법을 알아보려면 [이미지 로드](https://www.tensorflow.org/tutorials/load_data/images) 튜토리얼을 참조하세요.\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "ytHhsYmO52zy"
      },
      "outputs": [],
      "source": [
        "(train_ds, val_ds, test_ds), metadata = tfds.load(\n",
        "    'tf_flowers',\n",
        "    split=['train[:80%]', 'train[80%:90%]', 'train[90%:]'],\n",
        "    with_info=True,\n",
        "    as_supervised=True,\n",
        ")"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "MjxEJtCwsnmm"
      },
      "source": [
        "꽃 데이터세트에는 5개의 클래스가 있습니다."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "wKwx7vQuspxz"
      },
      "outputs": [],
      "source": [
        "num_classes = metadata.features['label'].num_classes\n",
        "print(num_classes)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "zZAQW44949uw"
      },
      "source": [
        "데이터세트에서 이미지를 검색하고 이를 사용하여 데이터 증강을 수행하겠습니다."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "kXlx1lCr5Bip"
      },
      "outputs": [],
      "source": [
        "get_label_name = metadata.features['label'].int2str\n",
        "\n",
        "image, label = next(iter(train_ds))\n",
        "_ = plt.imshow(image)\n",
        "_ = plt.title(get_label_name(label))"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "vdJ6XA4q2nqK"
      },
      "source": [
        "## Keras 전처리 레이어 사용하기"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "5BTGz5AQ9LcD"
      },
      "source": [
        "참고: 이 섹션에서 소개하는 [Keras 전처리 레이어](https://www.tensorflow.org/api_docs/python/tf/keras/layers/experimental/preprocessing)는 현재 실험적 단계입니다."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "GRMPnfzBB2hw"
      },
      "source": [
        "### 크기 및 배율 조정하기\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "jhG7gSWmUMJx"
      },
      "source": [
        "전처리 레이어를 사용하여 이미지를 일관된 모양으로 [크기 조정](https://www.tensorflow.org/api_docs/python/tf/keras/layers/experimental/preprocessing/Resizing)하고 픽셀 값의 [배율을 조정](https://www.tensorflow.org/api_docs/python/tf/keras/layers/experimental/preprocessing/Rescaling)할 수 있습니다."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "jMM3b85e3yhd"
      },
      "outputs": [],
      "source": [
        "IMG_SIZE = 180\n",
        "\n",
        "resize_and_rescale = tf.keras.Sequential([\n",
        "  layers.experimental.preprocessing.Resizing(IMG_SIZE, IMG_SIZE),\n",
        "  layers.experimental.preprocessing.Rescaling(1./255)\n",
        "])"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "4z8AV1WgnYNW"
      },
      "source": [
        "참고: 위의 배율 조정 레이어는 픽셀 값을 `[0,1]`로 표준화합니다. 그렇지 않고 `[-1,1]`을 원할 경우, `Rescaling(1./127.5, offset=-1)`을 작성하면 됩니다.\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "MQiTwsHJDHAD"
      },
      "source": [
        "이러한 레이어를 이미지에 적용한 결과를 볼 수 있습니다. "
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "X9OLuR1bC1Pd"
      },
      "outputs": [],
      "source": [
        "result = resize_and_rescale(image)\n",
        "_ = plt.imshow(result)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "yxAMg8Zql5lw"
      },
      "source": [
        "픽셀이 `[0-1]`에 있는지 확인할 수 있습니다."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "DPTB8IQmSeKM"
      },
      "outputs": [],
      "source": [
        "print(\"Min and max pixel values:\", result.numpy().min(), result.numpy().max())"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "fL6M7fuivAw4"
      },
      "source": [
        "### 데이터 증강"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "SL4Suj46ScfU"
      },
      "source": [
        "데이터 증강에도 전처리 레이어를 사용할 수 있습니다."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "V-4PugTE-4sl"
      },
      "source": [
        "몇 개의 전처리 레이어를 만들어 동일한 이미지에 반복적으로 적용 해 보겠습니다."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "Svu_5yfa_Jb7"
      },
      "outputs": [],
      "source": [
        "data_augmentation = tf.keras.Sequential([\n",
        "  layers.experimental.preprocessing.RandomFlip(\"horizontal_and_vertical\"),\n",
        "  layers.experimental.preprocessing.RandomRotation(0.2),\n",
        "])"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "kfzEuaNg69iU"
      },
      "outputs": [],
      "source": [
        "# Add the image to a batch\n",
        "image = tf.expand_dims(image, 0)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "eR4wwi5Q_UZK"
      },
      "outputs": [],
      "source": [
        "plt.figure(figsize=(10, 10))\n",
        "for i in range(9):\n",
        "  augmented_image = data_augmentation(image)\n",
        "  ax = plt.subplot(3, 3, i + 1)\n",
        "  plt.imshow(augmented_image[0])\n",
        "  plt.axis(\"off\")"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "jA17pEeS_2_-"
      },
      "source": [
        "`layers.RandomContrast`, `layers.RandomCrop`, `layers.RandomZoom` 등 데이터 증강에 사용할 수 있는 다양한 전처리 [레이어](https://www.tensorflow.org/api_docs/python/tf/keras/layers/experimental/preprocessing)가 있습니다."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "GG5RhIJtE0ng"
      },
      "source": [
        "### 전처리 레이어를 사용하는 두 가지 옵션\n",
        "\n",
        "중요한 절충을 통해 이러한 전처리 레이어를 사용할 수 있는 두 가지 방법이 있습니다."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "MxGvUT727Po6"
      },
      "source": [
        "#### 옵션 1: 전처리 레이어를 모델의 일부로 만들기"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "ULGJQjP6hHvu"
      },
      "outputs": [],
      "source": [
        "model = tf.keras.Sequential([\n",
        "  resize_and_rescale,\n",
        "  data_augmentation,\n",
        "  layers.Conv2D(16, 3, padding='same', activation='relu'),\n",
        "  layers.MaxPooling2D(),\n",
        "  # Rest of your model\n",
        "])"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "pc6ELneyhJN9"
      },
      "source": [
        "이 경우 유의해야 할 두 가지 중요한 사항이 있습니다.\n",
        "\n",
        "- 데이터 증강은 나머지 레이어와 동기적으로 기기에서 실행되며 GPU 가속을 이용합니다.\n",
        "\n",
        "- `model.save`를 사용하여 모델을 내보낼 때 전처리 레이어가 모델의 나머지 부분과 함께 저장됩니다. 나중에 이 모델을 배포하면 레이어 구성에 따라 이미지가 자동으로 표준화됩니다. 이를 통해 서버측 논리를 다시 구현해야 하는 노력을 덜 수 있습니다."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "syZwDSpiRXZP"
      },
      "source": [
        "참고: 데이터 증강은 테스트할 때 비활성화되므로 입력 이미지는 `model.fit`(`model.evaluate` 또는 `model.predict`가 아님) 호출 중에만 증강됩니다."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "B2X3JTeY_vfv"
      },
      "source": [
        "#### 옵션 2: 데이터세트에 전처리 레이어 적용하기"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "r1Bt7w5VhVDY"
      },
      "outputs": [],
      "source": [
        "aug_ds = train_ds.map(\n",
        "  lambda x, y: (resize_and_rescale(x, training=True), y))"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "HKqeahG2hVdV"
      },
      "source": [
        "이 접근 방식에서는 `Dataset.map`을 사용하여 증강 이미지 배치를 생성하는 데이터세트를 만듭니다. 이 경우에는 다음과 같습니다.\n",
        "\n",
        "- 데이터 증강은 CPU에서 비동기적으로 이루어지며 차단되지 않습니다. 아래와 같이 `Dataset.prefetch`를 사용하여 GPU에서 모델 훈련을 데이터 전처리와 중첩할 수 있습니다.\n",
        "- 이 경우, 전처리 레이어는 `model.save`를 호출할 때 모델과 함께 내보내지지 않습니다. 저장하기 전에 이 레이어를 모델에 연결하거나 서버측에서 다시 구현해야 합니다. 훈련 후, 내보내기 전에 전처리 레이어를 연결할 수 있습니다.\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "cgj51k9J7jfc"
      },
      "source": [
        "[이미지 분류](https://www.tensorflow.org/tutorials/images/classification) 튜토리얼에서 첫 번째 옵션의 예를 볼 수 있습니다. 여기에서는 두 번째 옵션을 살펴보겠습니다."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "31YwMQdrXKBP"
      },
      "source": [
        "### 데이터세트에 전처리 레이어 적용하기"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "WUgW-2LOGiOT"
      },
      "source": [
        "위에서 생성한 전처리 레이어로 훈련, 검증 및 테스트 데이터세트를 구성합니다. 또한 병렬 읽기 및 버퍼링된 프리페치를 사용하여 I/O 차단 없이 디스크에서 배치를 생성하여 성능을 높이도록 데이터세트를 구성합니다. [tf.data API로 성능 향상하기](https://www.tensorflow.org/guide/data_performance) 가이드에서 데이터세트 성능에 대해 자세히 알아볼 수 있습니다. "
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "eI7VdyqK767y"
      },
      "source": [
        "참고: 데이터 증강은 훈련 세트에만 적용해야 합니다."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "R5fGVMqlFxF7"
      },
      "outputs": [],
      "source": [
        "batch_size = 32\n",
        "AUTOTUNE = tf.data.experimental.AUTOTUNE\n",
        "\n",
        "def prepare(ds, shuffle=False, augment=False):\n",
        "  # Resize and rescale all datasets\n",
        "  ds = ds.map(lambda x, y: (resize_and_rescale(x), y), \n",
        "              num_parallel_calls=AUTOTUNE)\n",
        "\n",
        "  if shuffle:\n",
        "    ds = ds.shuffle(1000)\n",
        "\n",
        "  # Batch all datasets\n",
        "  ds = ds.batch(batch_size)\n",
        "\n",
        "  # Use data augmentation only on the training set\n",
        "  if augment:\n",
        "    ds = ds.map(lambda x, y: (data_augmentation(x, training=True), y), \n",
        "                num_parallel_calls=AUTOTUNE)\n",
        "\n",
        "  # Use buffered prefecting on all datasets\n",
        "  return ds.prefetch(buffer_size=AUTOTUNE)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "N86SFGMBHcx-"
      },
      "outputs": [],
      "source": [
        "train_ds = prepare(train_ds, shuffle=True, augment=True)\n",
        "val_ds = prepare(val_ds)\n",
        "test_ds = prepare(test_ds)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "9gplDz4ZV6kk"
      },
      "source": [
        "### 모델 훈련하기\n",
        "\n",
        "완성도를 높이기 위해 이제 이러한 데이터세트를 사용하여 모델을 훈련합니다. 이 모델은 정확성에 목표를 두고 조정되지 않았습니다(작동 방식을 시연하는 것이 목표임)."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "IODSymGhq9N6"
      },
      "outputs": [],
      "source": [
        "model = tf.keras.Sequential([\n",
        "  layers.Conv2D(16, 3, padding='same', activation='relu'),\n",
        "  layers.MaxPooling2D(),\n",
        "  layers.Conv2D(32, 3, padding='same', activation='relu'),\n",
        "  layers.MaxPooling2D(),\n",
        "  layers.Conv2D(64, 3, padding='same', activation='relu'),\n",
        "  layers.MaxPooling2D(),\n",
        "  layers.Flatten(),\n",
        "  layers.Dense(128, activation='relu'),\n",
        "  layers.Dense(num_classes)\n",
        "])"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "ZnRJr95WY68k"
      },
      "outputs": [],
      "source": [
        "model.compile(optimizer='adam',\n",
        "              loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True),\n",
        "              metrics=['accuracy'])"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "i_sDl9uZY9Mh"
      },
      "outputs": [],
      "source": [
        "epochs=5\n",
        "history = model.fit(\n",
        "  train_ds,\n",
        "  validation_data=val_ds,\n",
        "  epochs=epochs\n",
        ")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "V9PSf4qgiQJG"
      },
      "outputs": [],
      "source": [
        "loss, acc = model.evaluate(test_ds)\n",
        "print(\"Accuracy\", acc)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "0BkRvvsXb6SI"
      },
      "source": [
        "### 사용자 정의 데이터 증강\n",
        "\n",
        "사용자 정의 데이터 증강 레이어를 만들 수도 있습니다. 이 튜토리얼에서는 두 가지 방법을 소개합니다. 먼저, `layers.Lambda` 레이어를 생성합니다. 이것은 간결한 코드를 작성하는 좋은 방법입니다. 다음으로, 제어력을 높여주는 [서브 클래스 생성](https://www.tensorflow.org/guide/keras/custom_layers_and_models)을 통해 새 레이어를 작성합니다. 두 레이어는 확률에 따라 이미지의 색상을 무작위로 반전합니다. "
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "nMxEhIVXmAH0"
      },
      "outputs": [],
      "source": [
        "def random_invert_img(x, p=0.5):\n",
        "  if  tf.random.uniform([]) < p:\n",
        "    x = (255-x)\n",
        "  else:\n",
        "    x\n",
        "  return x"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "C0huNpxdmDKu"
      },
      "outputs": [],
      "source": [
        "def random_invert(factor=0.5):\n",
        "  return layers.Lambda(lambda x: random_invert_img(x, factor))\n",
        "\n",
        "random_invert = random_invert()"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "wAcOluP0TNG6"
      },
      "outputs": [],
      "source": [
        "plt.figure(figsize=(10, 10))\n",
        "for i in range(9):\n",
        "  augmented_image = random_invert(image)\n",
        "  ax = plt.subplot(3, 3, i + 1)\n",
        "  plt.imshow(augmented_image[0].numpy().astype(\"uint8\"))\n",
        "  plt.axis(\"off\")"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "Xd9XG2PLM5ZJ"
      },
      "source": [
        "다음으로, [서브 클래스 생성](https://www.tensorflow.org/guide/keras/custom_layers_and_models)을 통해 사용자 정의 레이어를 구현합니다."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "d11eExc-Ke-7"
      },
      "outputs": [],
      "source": [
        "class RandomInvert(layers.Layer):\n",
        "  def __init__(self, factor=0.5, **kwargs):\n",
        "    super().__init__(**kwargs)\n",
        "    self.factor = factor\n",
        "\n",
        "  def call(self, x):\n",
        "    return random_invert_img(x)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "qX-VQgkRL6fc"
      },
      "outputs": [],
      "source": [
        "_ = plt.imshow(RandomInvert()(image)[0])"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "B0nmllnXZO6T"
      },
      "source": [
        "위의 옵션 1과 2의 설명에 따라 이 두 레이어를 모두 사용할 수 있습니다."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "j7-k__2dAfX6"
      },
      "source": [
        "## tf.image 사용하기"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "NJco2x35EAMs"
      },
      "source": [
        "위의 `layers.preprocessing` 유틸리티는 편리합니다. 보다 세밀한 제어를 위해서는 `tf.data` 및 `tf.image`를 사용하여 고유한 데이터 증강 파이프라인 또는 레이어를 작성할 수 있습니다. [TensorFlow 애드온 이미지: 작업](https://www.tensorflow.org/addons/tutorials/image_ops) 및 [TensorFlow I/O: 색 공간 변환](https://www.tensorflow.org/io/tutorials/colorspace)도 확인해보세요."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "xR1RvjYkdd_i"
      },
      "source": [
        "꽃 데이터세트는 이전에 데이터 증강으로 구성되었으므로 다시 가져와서 새로 시작하겠습니다."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "JB-lAS0z9ZJY"
      },
      "outputs": [],
      "source": [
        "(train_ds, val_ds, test_ds), metadata = tfds.load(\n",
        "    'tf_flowers',\n",
        "    split=['train[:80%]', 'train[80%:90%]', 'train[90%:]'],\n",
        "    with_info=True,\n",
        "    as_supervised=True,\n",
        ")"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "rQ3pqBTS9hNj"
      },
      "source": [
        "작업할 이미지를 검색합니다."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "dDsPaAi8de_j"
      },
      "outputs": [],
      "source": [
        "image, label = next(iter(train_ds))\n",
        "_ = plt.imshow(image)\n",
        "_ = plt.title(get_label_name(label))"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "chelxcPtFiTF"
      },
      "source": [
        "다음 함수를 사용하여 원본 이미지와 증강 이미지를 나란히 시각화하고 비교하겠습니다."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "sN1ykjJCHikc"
      },
      "outputs": [],
      "source": [
        "def visualize(original, augmented):\n",
        "  fig = plt.figure()\n",
        "  plt.subplot(1,2,1)\n",
        "  plt.title('Original image')\n",
        "  plt.imshow(original)\n",
        "\n",
        "  plt.subplot(1,2,2)\n",
        "  plt.title('Augmented image')\n",
        "  plt.imshow(augmented)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "C5X4ijQYHmlt"
      },
      "source": [
        "### 데이터 증강"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "RRD9oujLHo6c"
      },
      "source": [
        "### 이미지 뒤집기\n",
        "\n",
        "이미지를 수직 또는 수평으로 뒤집습니다."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "1ZjVI24nIH0S"
      },
      "outputs": [],
      "source": [
        "flipped = tf.image.flip_left_right(image)\n",
        "visualize(image, flipped)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "6iD_lLibIL9q"
      },
      "source": [
        "### 이미지를 회색조로 만들기\n",
        "\n",
        "이미지를 회색조로 만듭니다."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "ikaMj0guIRtL"
      },
      "outputs": [],
      "source": [
        "grayscaled = tf.image.rgb_to_grayscale(image)\n",
        "visualize(image, tf.squeeze(grayscaled))\n",
        "_ = plt.colorbar()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "f-5yjIs4IZ7v"
      },
      "source": [
        "### 이미지 포화시키기\n",
        "\n",
        "채도 계수를 제공하여 이미지를 포화시킵니다."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "PHz-NosiInmz"
      },
      "outputs": [],
      "source": [
        "saturated = tf.image.adjust_saturation(image, 3)\n",
        "visualize(image, saturated)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "FWXiy8qfIqdC"
      },
      "source": [
        "### 이미지 밝기 변경하기\n",
        "\n",
        "밝기 계수를 제공하여 이미지의 밝기를 변경합니다."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "1hdG-j46I0nJ"
      },
      "outputs": [],
      "source": [
        "bright = tf.image.adjust_brightness(image, 0.4)\n",
        "visualize(image, bright)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "vjEOFEITJOr2"
      },
      "source": [
        "### 이미지 중앙 자르기\n",
        "\n",
        "이미지를 중앙에서 원하는 이미지 부분까지 자릅니다."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "RWkK5GFHJUKT"
      },
      "outputs": [],
      "source": [
        "cropped = tf.image.central_crop(image, central_fraction=0.5)\n",
        "visualize(image,cropped)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "unt76GebI3Gc"
      },
      "source": [
        "### 이미지 회전하기\n",
        "\n",
        "이미지를 90도 회전합니다."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "b19KuAhkJKR-"
      },
      "outputs": [],
      "source": [
        "rotated = tf.image.rot90(image)\n",
        "visualize(image, rotated)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "isrM-MZtpxTq"
      },
      "source": [
        "### 데이터세트에 증강 적용하기\n",
        "\n",
        "이전과 마찬가지로 `Dataset.map`을 사용하여 데이터 증강을 데이터세트에 적용합니다."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "1JKmx06lfcFr"
      },
      "outputs": [],
      "source": [
        "def resize_and_rescale(image, label):\n",
        "  image = tf.cast(image, tf.float32)\n",
        "  image = tf.image.resize(image, [IMG_SIZE, IMG_SIZE])\n",
        "  image = (image / 255.0)\n",
        "  return image, label"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "FvuNMF8qqRsD"
      },
      "outputs": [],
      "source": [
        "def augment(image,label):\n",
        "  image, label = resize_and_rescale(image, label)\n",
        "  # Add 6 pixels of padding\n",
        "  image = tf.image.resize_with_crop_or_pad(image, IMG_SIZE + 6, IMG_SIZE + 6) \n",
        "   # Random crop back to the original size\n",
        "  image = tf.image.random_crop(image, size=[IMG_SIZE, IMG_SIZE, 3])\n",
        "  image = tf.image.random_brightness(image, max_delta=0.5) # Random brightness\n",
        "  image = tf.clip_by_value(image, 0, 1)\n",
        "  return image, label"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "Khu7amifqbni"
      },
      "source": [
        "### 데이터세트 구성하기"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "khgl0CwEeZ-_"
      },
      "outputs": [],
      "source": [
        "train_ds = (\n",
        "    train_ds\n",
        "    .shuffle(1000)\n",
        "    .map(augment, num_parallel_calls=AUTOTUNE)\n",
        "    .batch(batch_size)\n",
        "    .prefetch(AUTOTUNE)\n",
        ") "
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "4PUbgIYJebED"
      },
      "outputs": [],
      "source": [
        "val_ds = (\n",
        "    val_ds\n",
        "    .map(resize_and_rescale, num_parallel_calls=AUTOTUNE)\n",
        "    .batch(batch_size)\n",
        "    .prefetch(AUTOTUNE)\n",
        ")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "nQvQzKoQgBw2"
      },
      "outputs": [],
      "source": [
        "test_ds = (\n",
        "    test_ds\n",
        "    .map(resize_and_rescale, num_parallel_calls=AUTOTUNE)\n",
        "    .batch(batch_size)\n",
        "    .prefetch(AUTOTUNE)\n",
        ")"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "hKwCA6AOjTrc"
      },
      "source": [
        "이제 이러한 데이터세트를 사용하여 이전에 표시한 대로 모델을 훈련할 수 있습니다."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "YypDihDlj0no"
      },
      "source": [
        "## 다음 단계\n",
        "\n",
        "이 튜토리얼에서는 [Keras 전처리 레이어](https://www.tensorflow.org/api_docs/python/tf/keras/layers/experimental/preprocessing/) 및 `tf.image`를 사용한 데이터 증강 방법을 보여주었습니다. 모델 내부에 전처리 레이어를 포함하는 방법을 알아보려면 [이미지 분류](https://www.tensorflow.org/tutorials/images/classification) 튜토리얼을 참조하세요. [기본 텍스트 분류](https://www.tensorflow.org/tutorials/keras/text_classification) 튜토리얼에 나와 있는 것처럼 전처리 레이어가 텍스트를 분류하는 데 어떤 도움을 주는지 알아볼 수도 있습니다. 이 [가이드](https://www.tensorflow.org/guide/data)에서 `tf.data`에 대해 자세히 알아볼 수 있으며 [여기](https://www.tensorflow.org/guide/data_performance)에서 성능을 높이도록 입력 파이프라인을 구성하는 방법을 알아볼 수 있습니다."
      ]
    }
  ],
  "metadata": {
    "accelerator": "GPU",
    "colab": {
      "collapsed_sections": [],
      "name": "data_augmentation.ipynb",
      "toc_visible": true
    },
    "kernelspec": {
      "display_name": "Python 3",
      "name": "python3"
    }
  },
  "nbformat": 4,
  "nbformat_minor": 0
}
